﻿using Minecraft.Config;
using Minecraft.Config.Csv.CsvCls;
using Minecraft.Model;
using Minecraft.Model.ZombiesBrush;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Minecraft.ServerHall
{
	public static class ZombiesbrushExt
	{
		/// <summary>
		/// 经验的改变导致尸潮的处理
		/// </summary>
		/// <param name="session"></param>
		public static void ExperienceChange(this MinecraftSession session)
		{
			if (!session.minecraftSessionInfo.player.IsCanBrushMonster_Convert)
			{
				//是否达到刷怪的条件（等级达到10级以上）
				if (session.minecraftSessionInfo.player.Level_Convert >= MinecraftConfig.BrushMonsterUnlockedLevel)
				{
					session.minecraftSessionInfo.player.IsCanBrushMonster = 1;
					session.minecraftSessionInfo.player.ZombieContinuityFailNum = 0;
					//开始第一波尸潮
					var timeNow = DateTimeOffset.Now;
					var modZombieattackInfo = CsvConfig.GetzombieattackDict().Select(m => m.Value).OrderBy(m => m.Id_Convert).FirstOrDefault();
					session.minecraftSessionInfo.zombiesbrushInfo = new ZombiesbrushModel
					{
						PlayerId = session.minecraftSessionInfo.player.PlayerId,
						ZombieAttackId = modZombieattackInfo.Id_Convert,
						ZombieAttackStartTime = timeNow,
						ZombiesItemIdAndNums = modZombieattackInfo.Zombies,
						ZombieAttackFinishTime = timeNow.AddSeconds(modZombieattackInfo.GetZombiesbrushMaxCycleSecond()),
					};
				}
			}
		}
		/// <summary>
		/// 获取当前尸潮的信息（内部同时更新尸潮信息，以及返回玩家在间断期间过了尸潮最大周期的个数）
		/// （注意：目前只有产出家具计入模拟计算的范畴，暂时没有幸存者，这就导致了玩家离开基地后，基地没有了反抗能力，所以如果玩家不在基地的时间过长，则默认尸潮失败）
		/// </summary>
		/// <param name="session"></param>
		/// <returns></returns>
		public static ZombiesbrushRespInfo GetZombiesbrushState(this MinecraftSession session)
		{
			int ontheWayRemainSecond = 0; //尸潮正在路上时，还剩余多少秒到达基地
			ZombiesbrushModel zombiesbrushModel = session.minecraftSessionInfo.zombiesbrushInfo;
			EnumZombiesbrushState enumZombiesbrushState = EnumZombiesbrushState.Unknown;
			EnumZombieLastSuccessOrFailureState enumZombieLastSuccessOrFailureState = EnumZombieLastSuccessOrFailureState.Unknown;

			if (!session.minecraftSessionInfo.player.IsCanBrushMonster_Convert)
			{
				enumZombiesbrushState = EnumZombiesbrushState.NotAchieveCondition;
			}
			else
			{

				var timeNow = DateTimeOffset.Now;
				//当前时间与各个时间作对比
				if (timeNow < zombiesbrushModel.ZombieAttackStartTime)
				{
					throw new Exception($"当前时间小于数据库记录的尸潮开始时间，可能在更新尸潮信息是时疏忽了");
				}
				var modZombieattackInfo = CsvConfig.GetMod_ZombieAttackInfoById(zombiesbrushModel.ZombieAttackId.ToString());
				if (modZombieattackInfo == null)
				{
					throw new Exception($"modZombieattackInfo 信息为空【zombiesbrushModel.ZombieAttackId：{zombiesbrushModel.ZombieAttackId}】");
				}
				if (timeNow < zombiesbrushModel.ZombieAttackStartTime.AddSeconds(modZombieattackInfo.Cooling_time_Convert))
				{
					enumZombiesbrushState = EnumZombiesbrushState.OntheWay;
					ontheWayRemainSecond = (int)(zombiesbrushModel.ZombieAttackStartTime.AddSeconds(modZombieattackInfo.Cooling_time_Convert) - timeNow).TotalSeconds;
				}
				else
				{
					if (timeNow < zombiesbrushModel.ZombieAttackFinishTime)
					{
						enumZombiesbrushState = EnumZombiesbrushState.UnderAttack;
						//模拟计算
						session.ZombiesbrushAnalogComputation(timeNow);
					}
					else
					{
						int modSecond = ((int)(timeNow - zombiesbrushModel.ZombieAttackFinishTime).TotalSeconds) % modZombieattackInfo.GetZombiesbrushMaxCycleSecond();
						if (modSecond < modZombieattackInfo.Cooling_time_Convert)
						{
							enumZombiesbrushState = EnumZombiesbrushState.OntheWay;
						}
						else
						{
							enumZombiesbrushState = EnumZombiesbrushState.UnderAttack;
						}
						enumZombieLastSuccessOrFailureState = session.SetNewZombiesbrushInfo();
						//模拟计算
						session.ZombiesbrushAnalogComputation(timeNow);
					}
				}
			}

			return new ZombiesbrushRespInfo
			{
				zombieBrushId = zombiesbrushModel.ZombieAttackId,
				enumZombiesbrushState = enumZombiesbrushState,
				enumZombieLastSuccessOrFailureState = enumZombieLastSuccessOrFailureState,
				zombiesBrushInfoList = zombiesbrushModel.GetZombiesItemIdAndNumsList_Convert(),
				ontheWayRemainSecond = ontheWayRemainSecond,
			};

		}
		/// <summary>
		/// 尸潮模拟计算
		/// </summary>
		public static void ZombiesbrushAnalogComputation(this MinecraftSession session, DateTimeOffset timeNow)
		{
			ZombiesbrushModel zombiesbrushModel = session.minecraftSessionInfo.zombiesbrushInfo;
			//僵尸入侵后玩家是否初次进入基地
			var player = session.minecraftSessionInfo.player;
			int intrusionsNum = 0; //入侵次数
			if (player.RecentlyIntoBaseTime >= zombiesbrushModel.ZombieAttackStartTime)
			{
				if (player.LastIntoBaseTime < zombiesbrushModel.ZombieAttackStartTime)
				{
					//是第一次进入
					intrusionsNum = (int)(player.RecentlyIntoBaseTime - zombiesbrushModel.ZombieAttackStartTime).TotalSeconds / MinecraftConfig.BrushMonsterLossInterval;
				}
				else
				{
					//不是第一次进入
					intrusionsNum = (int)(player.RecentlyIntoBaseTime - player.LastIntoBaseTime).TotalSeconds / MinecraftConfig.BrushMonsterLossInterval;
				}
				if (intrusionsNum > 3)
				{
					intrusionsNum = 3;
				}
				//僵尸总量
				var zombieNum = zombiesbrushModel.GetZombiesItemIdAndNumsList_Convert().Sum(m => m.Num);
				for (int intrusionsIndex = 0; intrusionsIndex < intrusionsNum; intrusionsIndex++)
				{
					//获取未损坏的产出家具
					var furnitureOutputList = session.minecraftSessionInfo.furnitureOutputList.Where(m => m.Hp > 0).ToList();
					if (furnitureOutputList.Any())
					{
						List<ZombiesChooseFurnitureOutputInfo> zombiesChooseFurnitureOutputInfoList = new List<ZombiesChooseFurnitureOutputInfo>();
						for (int zombieIndex = 0; zombieIndex < zombieNum; zombieIndex++)
						{
							//僵尸会在基地中随机选择自己想要破坏的家具
							List<int> randomList = new List<int>();
							ListHelper.RandomNotEqualList(ref randomList, 0, furnitureOutputList.Count() - 1, 1);
							var zombiesChooseFurnitureOutputInfo = zombiesChooseFurnitureOutputInfoList.FirstOrDefault(m => m.furnitureOutputIndex == randomList.First());
							if (zombiesChooseFurnitureOutputInfo == null)
							{
								zombiesChooseFurnitureOutputInfo = new ZombiesChooseFurnitureOutputInfo
								{
									furnitureOutputIndex = randomList.First(),
									zombieNum = 1
								};
								zombiesChooseFurnitureOutputInfoList.Add(zombiesChooseFurnitureOutputInfo);
							}
							else
							{
								zombiesChooseFurnitureOutputInfo.zombieNum++;
							}
						}
						//根据摧毁概率随机摧毁产出家具
						Random random = new Random(DateTimeHelper.GetTotalSecondsIntOfThisYear() + intrusionsIndex);
						foreach (var zombiesChooseFurnitureOutputInfo in zombiesChooseFurnitureOutputInfoList)
						{
							var r = random.Next(1, 101);
							if (r <= 10 * zombiesChooseFurnitureOutputInfo.zombieNum)
							{
								var furnitureOutputId = furnitureOutputList[zombiesChooseFurnitureOutputInfo.furnitureOutputIndex].FurnitureId;
								session.minecraftSessionInfo.furnitureOutputList.FirstOrDefault(m => m.FurnitureId == furnitureOutputId).Hp = 0;
							}
						}
					}
				}
			}
			else
			{
				throw new Exception($" (player.RecentlyIntoBaseTime < zombiesbrushModel.ZombieAttackStartTime) 逻辑错误");
			}
		}
		/// <summary>
		/// 设置最新的NewZombiesbrushInfo（数据库），并返回上一次尸潮的胜负状态
		/// </summary>
		/// <param name="timeNow"></param>
		/// <param name="modSecond"></param>
		/// <param name="session"></param>
		/// <param name="cycleNum"></param>
		/// <param name="zombiesbrushModel"></param>
		/// <param name="modZombieattackInfo"></param>
		public static EnumZombieLastSuccessOrFailureState SetNewZombiesbrushInfo(this MinecraftSession session)
		{
			var timeNow = DateTimeOffset.Now;
			ZombiesbrushModel zombiesbrushModel = session.minecraftSessionInfo.zombiesbrushInfo;
			var modZombieattackInfo = CsvConfig.GetMod_ZombieAttackInfoById(zombiesbrushModel.ZombieAttackId.ToString());
			int modSecond = ((int)(timeNow - zombiesbrushModel.ZombieAttackFinishTime).TotalSeconds) % modZombieattackInfo.GetZombiesbrushMaxCycleSecond();
			var attackStartTime = timeNow.AddSeconds(-modSecond);
			EnumZombieLastSuccessOrFailureState enumZombieLastSuccessOrFailureState = EnumZombieLastSuccessOrFailureState.Unknown;
			//可能玩家有一段时间没有查询了，弥补时间记录空缺（cycleNum表示玩家在间断期间过了尸潮最大周期的个数）
			int cycleNum = ((int)(timeNow - zombiesbrushModel.ZombieAttackFinishTime).TotalSeconds) / modZombieattackInfo.GetZombiesbrushMaxCycleSecond();
			if (cycleNum <= 0)
			{
				if ((int)(zombiesbrushModel.ZombieAttackFinishTime - zombiesbrushModel.ZombieAttackStartTime).TotalSeconds < modZombieattackInfo.GetZombiesbrushMaxCycleSecond())
				{
					//上一次的尸潮：成功抵御僵尸入侵
					enumZombieLastSuccessOrFailureState = EnumZombieLastSuccessOrFailureState.Success;
					session.minecraftSessionInfo.player.ZombieContinuityFailNum = 0;

					//奖励计算
					session.ZombieBrushReward();
					//如果上一次尸潮抵御成功，则获取最新尸潮配置
					var modZombieattackList = CsvConfig.GetzombieattackDict().Select(m => m.Value).OrderBy(m => m.Id_Convert).ToList();
					var index = modZombieattackList.FindIndex(m => m.Id_Convert == modZombieattackInfo.Id_Convert);
					var newIndex = 0;
					if (modZombieattackList.Count() - 2 >= index)
					{
						newIndex = index + 1;
					}
					else
					{
						newIndex = index;
					}
					var newModZombieattackInfo = modZombieattackList[newIndex];
					if (newModZombieattackInfo == null)
					{
						throw new Exception($"newModZombieattackInfo 信息为空");
					}
					session.minecraftSessionInfo.zombiesbrushInfo = new ZombiesbrushModel
					{
						PlayerId = session.minecraftSessionInfo.player.PlayerId,
						ZombieAttackId = newModZombieattackInfo.Id_Convert,
						ZombiesItemIdAndNums = newModZombieattackInfo.Zombies,
						ZombieAttackStartTime = attackStartTime,
						ZombieAttackFinishTime = attackStartTime.AddSeconds(modZombieattackInfo.GetZombiesbrushMaxCycleSecond()),
					};
				}
				else
				{
					//上一次的尸潮：失败
					enumZombieLastSuccessOrFailureState = EnumZombieLastSuccessOrFailureState.Failure;
					session.minecraftSessionInfo.player.ZombieContinuityFailNum = 1;
					//上次失败了，这次的尸潮要继续沿用上次失败的尸潮配置
					session.minecraftSessionInfo.zombiesbrushInfo.ZombiesItemIdAndNums = modZombieattackInfo.Zombies;
					session.minecraftSessionInfo.zombiesbrushInfo.ZombieAttackStartTime = attackStartTime;
					session.minecraftSessionInfo.zombiesbrushInfo.ZombieAttackFinishTime = attackStartTime.AddSeconds(modZombieattackInfo.GetZombiesbrushMaxCycleSecond());
				}
			}
			else
			{
				//上一次的尸潮：失败
				enumZombieLastSuccessOrFailureState = EnumZombieLastSuccessOrFailureState.Failure;
				session.minecraftSessionInfo.player.ZombieContinuityFailNum = cycleNum + 1;
				//上次失败了，这次的尸潮要继续沿用上次失败的尸潮配置
				session.minecraftSessionInfo.zombiesbrushInfo.ZombiesItemIdAndNums = modZombieattackInfo.Zombies;
				session.minecraftSessionInfo.zombiesbrushInfo.ZombieAttackStartTime = attackStartTime;
				session.minecraftSessionInfo.zombiesbrushInfo.ZombieAttackFinishTime = attackStartTime.AddSeconds(modZombieattackInfo.GetZombiesbrushMaxCycleSecond());
			}
			return enumZombieLastSuccessOrFailureState;
		}
		/// <summary>
		/// 尸潮奖励计算
		/// </summary>
		/// <param name="session"></param>
		public static void ZombieBrushReward(this MinecraftSession session)
		{
			//var mod_ZombieAttackInfo = CsvConfig.GetMod_ZombieAttackInfoById(ZombieAttackId.ToString());
			//if (mod_ZombieAttackInfo == null)
			//{
			//	throw new Exception($"mod_ZombieAttackInfo 配置信息为空【ZombieAttackId：{ZombieAttackId}】");
			//}

		}
		public static List<ZombiesBrushInfo> GetZombiesItemIdAndNumsList_Convert(this ZombiesbrushModel zombiesbrushModel)
		{
			List<ZombiesBrushInfo> zombiesBrushInfoList = new List<ZombiesBrushInfo>();
			var strs = zombiesbrushModel.ZombiesItemIdAndNums.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
			foreach (var str in strs)
			{
				var items = str.Split(new char[] { '#' }, StringSplitOptions.RemoveEmptyEntries);
				ZombiesBrushInfo modZombiesBrushInfo = new ZombiesBrushInfo
				{
					ActorId = items[0],
					Num = int.Parse(items[1])
				};
				zombiesBrushInfoList.Add(modZombiesBrushInfo);
			}
			return zombiesBrushInfoList;
		}

		/// <summary>
		/// 针对 ZombiesItemIdAndNums 字段的修改要从对象列表转换成字符串
		/// </summary>
		/// <param name="furniture"></param>
		/// <param name="furnitureOutputMaterialGoodsInfo"></param>
		public static void TransformListToOutput_UpgradeMaterialGoodsItemIdsPosAndNums_Convert(this ZombiesbrushModel zombiesbrushModel,
			ZombiesBrushInfo zombiesBrushInfo)
		{
			var list = zombiesbrushModel.GetZombiesItemIdAndNumsList_Convert();
			var index = list.FindIndex(m => m.ActorId == zombiesBrushInfo.ActorId);
			if (index >= 0)
			{
				list.RemoveAt(index);
			}
			list.Add(zombiesBrushInfo);
			zombiesbrushModel.ZombiesItemIdAndNums = string.Join("|", list.ToList().ConvertAll(info =>
			{
				return string.Join("#", info.ActorId, info.Num);
			}).ToArray());
		}
	}
}
